package com.zhou.project.configurations.security.fifter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhou.project.components.base.result.ResultCode;
import com.zhou.project.components.base.result.ResultData;
import com.zhou.project.components.redis.RedisComponent;
import com.zhou.project.configurations.security.jwt.JwtWebToken;
import lombok.SneakyThrows;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.ObjectUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class LoginFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;

    // spring security
    private JwtWebToken jwtWebToken;
    private RedisComponent redisComponent;
    public LoginFilter(AuthenticationManager authenticationManager, JwtWebToken jwtWebToken,RedisComponent redisComponent) {
        super(authenticationManager);
        this.authenticationManager=authenticationManager;
        this.jwtWebToken = jwtWebToken;
        this.redisComponent = redisComponent;
    }

    /**
     * 拦截客户端请求，执行参数收集工作
     * @param request 请求
     * @param response 响应
     * @return
     * @throws AuthenticationException
     */
    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {


        //如果有手机端 又有网页版
//        request.getContentType();

            //获取前端请求中json数据
            ObjectMapper mapper = new ObjectMapper();
            //把json数据转为Map对象
            InputStream inputStream = request.getInputStream();
            Map<String,Object> data = mapper.readValue(inputStream, Map.class);
            // 封装 spring security token: 令牌
            // return new UsernamePasswordAuthenticationToken(data.get("username"),data.get("password"));
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(data.get("username"),data.get("password")));
    }

    /**
     * 认证成功后回调函数
     * @param request       请求
     * @param response      响应
     * @param chain         过滤器链
     * @param authResult    认证对象
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        //如果前面还有过滤器必须放行，
//        chain.doFilter(request,response);
        /**
         * 生成凭证（令牌） token
         * 1.jwt：json web token
         * 2.uuid + redis:
         *  RBAC: role based access of control(基于角色的访问控制)
         *  key: uuid
         *  value:username
         */
        //1.获得用户账号
        User user =(User) authResult.getPrincipal();
        //2.通过登录账号生成认证token
        String token = UUID.randomUUID().toString();
        Map<String,Object> hash=new HashMap<>();
        hash.put("username",user.getUsername());
        hash.put("lastTime", System.currentTimeMillis());

        //将获得的权限 也加入到redis
        List<String> authorities = new ArrayList<>();
        user.getAuthorities().forEach((code->{
            authorities.add(code.getAuthority());
        }));
        hash.put("authorities",authorities);

        redisComponent.hmset(token,hash,600);

//        redisComponent.set(token,user.getUsername(),600);
//        String token=jwtWebToken.createToken(user.getUsername(),3600);
        //3.写入客户端
        ResultData.response(response,ResultData.success(ResultCode.USER_LOGIN_SUCCESS,token));

    }

    /**
     * 认证失败后回调函数
     * @param request       请求
     * @param response      响应
     * @param exception     异常
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        //封装错误
        ResultCode code = ResultCode.USER_LOGIN_OTHER_ERROR;
        if (exception instanceof UsernameNotFoundException)
            code = ResultCode.USER_NOT_EXIST;
        else if (exception instanceof BadCredentialsException)
            code = ResultCode.USER_PASS_ERROR;
        else if (exception instanceof InternalAuthenticationServiceException)
            code = ResultCode.USER_ACCOUNT_LOCKED;
        //封装了 code message 放回响应
        ResultData.response(response,ResultData.failure(code));
    }
}
